home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / GUSI 1.4.1 / GUSI / GUSIFile.cp < prev    next >
Encoding:
Text File  |  1994-05-01  |  27.6 KB  |  1,427 lines  |  [TEXT/MPS ]

  1. /*********************************************************************
  2. Project    :    GUSI                -    Grand Unified Socket Interface
  3. File        :    GUSIFile.cp        -    Implementation of file calls
  4. Author    :    Matthias Neeracher <neeri@iis.ethz.ch>
  5. Language    :    MPW C
  6.  
  7. $Log: GUSIFile.cp,v $
  8. Revision 1.2  1994/05/01  23:37:55  neeri
  9. Added utime().
  10. Fixed stat() permissions for locked files.
  11.  
  12. Revision 1.1  1994/03/08  23:51:24  neeri
  13. Initial revision
  14.  
  15. Revision 0.34  1993/09/11  00:00:00  neeri
  16. Trying to avoid stream.h unless absolutely necessary    
  17.  
  18. Revision 0.33  1993/08/25  00:00:00  neeri
  19. Need 2 include TextUtils since E.T.O. #12
  20.  
  21. Revision 0.32  1993/07/17  00:00:00  neeri
  22. Adapt to BSD 4.3, scandir
  23.  
  24. Revision 0.31  1993/06/27  00:00:00  neeri
  25. f?truncate
  26.  
  27. Revision 0.30  1993/02/23  00:00:00  neeri
  28. fgetfileinfo
  29.  
  30. Revision 0.29  1993/02/01  00:00:00  neeri
  31. Made nlink for directories return something meaningful
  32.  
  33. Revision 0.28  1993/01/15  00:00:00  neeri
  34. rename() has to be more careful about renaming order
  35.  
  36. Revision 0.27  1993/01/15  00:00:00  neeri
  37. choose() should *not* count the string terminator.
  38.  
  39. Revision 0.26  1993/01/03  00:00:00  neeri
  40. Respect configuration
  41.  
  42. Revision 0.25  1993/01/01  00:00:00  neeri
  43. fsetfileinfo
  44.  
  45. Revision 0.24  1992/12/20  00:00:00  neeri
  46. do_putfile now respects default
  47.  
  48. Revision 0.23  1992/12/13  00:00:00  neeri
  49. stat now returns DirID/FileNo, not parID for the ino field
  50.  
  51. Revision 0.22  1992/12/08  00:00:00  neeri
  52. getcwd()
  53.  
  54. Revision 0.21  1992/11/28  00:00:00  neeri
  55. TEXT files are now considered executable
  56.  
  57. Revision 0.20  1992/11/15  00:00:00  neeri
  58. Rename GUSIFSp_P.h to TFileSpec.h (there we go again)
  59.  
  60. Revision 0.19  1992/10/28  00:00:00  neeri
  61. Forgot to change to dirent
  62.  
  63. Revision 0.18  1992/09/15  00:00:00  neeri
  64. Slight error in do_stat()
  65.  
  66. Revision 0.17  1992/09/12  00:00:00  neeri
  67. Rename Paths.h to GUSIFSp_P.h
  68.  
  69. Revision 0.16  1992/09/08  00:00:00  neeri
  70. readlink()
  71.  
  72. Revision 0.15  1992/09/06  00:00:00  neeri
  73. Adapt alias resolution to new libraries
  74.  
  75. Revision 0.14  1992/07/13  00:00:00  neeri
  76. CopyIconFamily
  77.  
  78. Revision 0.13  1992/06/27  00:00:00  neeri
  79. choose()
  80.  
  81. Revision 0.12  1992/06/26  00:00:00  neeri
  82. symlink is starting to work
  83.  
  84. Revision 0.11  1992/06/21  00:00:00  neeri
  85. symlink()
  86.  
  87. Revision 0.10  1992/06/15  00:00:00  neeri
  88. Separated path stuff
  89.  
  90. Revision 0.9  1992/05/21  00:00:00  neeri
  91. Implemented select()
  92.  
  93. Revision 0.8  1992/04/20  00:00:00  neeri
  94. C++ rewrite
  95.  
  96. Revision 0.7  1992/04/05  00:00:00  neeri
  97. lseek
  98.  
  99. Revision 0.6  1992/03/22  00:00:00  neeri
  100. Adapted for GUSI, change chdir stuff
  101.  
  102. Revision 0.5  1992/02/11  00:00:00  neeri
  103. Incorporated bug fix by John Reekie
  104.  
  105. Revision 0.4  1991/12/12  00:00:00  neeri
  106. FSp2RelPath
  107.  
  108. Revision 0.3  1991/12/09  00:00:00  neeri
  109. Radical overhaul
  110.  
  111. Revision 0.2  1991/05/28  00:00:00  neeri
  112. isatty()
  113.  
  114. Revision 0.1  1991/05/28  00:00:00  neeri
  115. Created
  116.  
  117. *********************************************************************/
  118.  
  119. #include "GUSI_P.h"
  120. #include "TFileSpec.h"
  121.  
  122. #include <Errors.h>
  123. #include <Resources.h>
  124. #include <Script.h>
  125. #include <Finder.h>
  126. #include <Folders.h>
  127. #include <Devices.h>
  128. #include <Memory.h>
  129. #include <Aliases.h>
  130. #include <string.h>
  131. #include <PLStringFuncs.h>
  132. #include <ioctl.h>
  133. #include <fcntl.h>
  134. #include <errno.h>
  135. #ifdef GUSI_FILE_DEBUG
  136. #include <stream.h>
  137. #endif
  138. #include <StdLib.h>
  139. #include <Time.h>
  140. #include <TextUtils.h>
  141. #include "unistd.h"
  142. #include "utime.h"
  143.  
  144. FileSocketDomain    FileSockets;
  145.  
  146. class FileSocket : public Socket {
  147.     friend class FileSocketDomain;
  148. protected:
  149.     int    fd;
  150.                     FileSocket(int fd)    :    fd(fd)    {}
  151. public:
  152.     virtual int    read(void * buffer, int buflen);
  153.     virtual int write(void * buffer, int buflen);
  154.     virtual int    fcntl(unsigned int cmd, int arg);
  155.     virtual int    ioctl(unsigned int request, void *argp);
  156.     virtual int    fstat(struct stat * buf);
  157.     virtual long lseek(long offset, int whence);
  158.     virtual int ftruncate(long offset);
  159.     virtual int    isatty();
  160.     virtual int select(Boolean * canRead, Boolean * canWrite, Boolean * exception);
  161.     virtual         ~FileSocket();
  162. };
  163.  
  164. /*********************** Prototypes for stdio ***********************/
  165.  
  166. extern "C" {
  167. int file_open(const char * name, int flags);
  168. int file_close(int s);
  169. int file_read(int s, char *buffer, unsigned buflen);
  170. int file_write(int s, char *buffer, unsigned buflen);
  171. int file_fcntl(int s, unsigned int cmd, int arg);
  172. int file_dup(int s);
  173. int file_ioctl(int d, unsigned int request, long *argp);  /* argp is really a caddr_t */
  174. long file_lseek(int fd, long offset, int whence);
  175. int file_faccess(char *fileName, unsigned int cmd, long * arg);
  176. }
  177.  
  178. /********************* FileSocketDomain members *********************/
  179.  
  180. Socket * FileSocketDomain::stdopen(int fd)
  181. {
  182.     return new FileSocket(fd);
  183. }
  184.  
  185. Boolean IsDevice(const char * fn)
  186. {
  187.     return     (    
  188.         (fn[0] | 0x20) == 'd'
  189.     && (fn[1] | 0x20) == 'e'
  190.     && (fn[2] | 0x20) == 'v'
  191.     && fn[3] == ':');
  192. }
  193.  
  194. static int File_error(OSErr err)
  195. {
  196.     switch (err) {
  197.     case noErr:
  198.         errno = 0;
  199.         
  200.         return 0;
  201.     case bdNamErr:
  202.         return GUSI_error(ENOTDIR);
  203.     case fnfErr:
  204.     case dirNFErr:
  205.         return GUSI_error(ENOENT);
  206.     case dupFNErr:
  207.         return GUSI_error(EEXIST);
  208.     case dirFulErr:
  209.         return GUSI_error(ENOSPC);
  210.     case fBsyErr:
  211.         return GUSI_error(EIO);
  212.     default:
  213.         return GUSI_error(EINVAL);
  214.     }
  215. }
  216.  
  217. Socket * FileSocketDomain::open(const char * filename, int oflag)
  218. {
  219.     int            fd;
  220.     Boolean        fresh;
  221.     char *        name;
  222.     
  223.     if (IsDevice(filename))    {
  224.         DeviceSocketDomain *     dom;
  225.         Socket *                     sock;
  226.         
  227.         // Try to hand it off to a specialized device handler
  228.  
  229.         for (dom = DeviceSocketDomain::firstDev; dom; dom = dom->nextDev) 
  230.             if ((sock = dom->open(filename+4, oflag)) != DeviceSocketDomain::TryNextDevice)
  231.                 return sock;
  232.         
  233.         fresh    =    false;
  234.         fd     =     file_open(filename, oflag);
  235.     } else {
  236.         TFileSpec spec(filename, oflag & O_ALIAS);
  237.         
  238.         if (spec.Error())    {
  239.             File_error(spec.Error());
  240.             
  241.             return nil;
  242.         }
  243.         
  244.         fresh    = (oflag & O_CREAT) && !spec.Exists();
  245.         fd        = file_open(name = spec.RelPath(), oflag);
  246.         
  247.         if ((fd != -1) && fresh)
  248.             GUSIConfig.SetDefaultFType(spec);
  249.     }
  250.     
  251.     if (fd == -1)
  252.         return nil;
  253.     
  254.     Socket * sock    =    new FileSocket(fd);
  255.     
  256.     if (!sock)    {
  257.         file_close(fd);
  258.         
  259.         if (fresh)
  260.             remove(name);
  261.     } 
  262.     
  263.     return sock;
  264. }
  265.  
  266. #define SFSaveDisk        (* (short *) 0x0214)
  267. #define CurDirStore        (* (long *)  0x0398)
  268.  
  269. static long     currentDir;
  270. static SFReply    reply;
  271. static char *    customPrompt;
  272.  
  273. static int do_getfile(
  274.                     TFileSpec *     defaultFile, 
  275.                     TFileSpec *     result,
  276.                     short                numTypes,
  277.                     SFTypeList        types)
  278. {
  279.     Point        myPoint    =    {75, 75};
  280.     
  281.     if (defaultFile) {
  282.         *defaultFile += "\p";
  283.         
  284.         SFSaveDisk     = -defaultFile->vRefNum;
  285.         CurDirStore = defaultFile->parID;
  286.     }
  287.     
  288.     SFGetFile(myPoint, "\p", NULL, numTypes, types, NULL, &reply);
  289.     
  290.     if (reply.good)
  291.         *result = TFileSpec(reply.vRefNum, reply.fName);
  292.     
  293.     return reply.good;
  294. }
  295.  
  296. static pascal Boolean FolderFFilter(ParmBlkPtr p)
  297. {
  298.     return !(p->fileParam.ioFlAttrib & ioDirMask);
  299. }
  300.  
  301. static ControlHandle GetDlgCtrl(DialogPtr dlg, short item)
  302. {
  303.     short     kind;
  304.     Handle    hdl;
  305.     Rect        box;
  306.     
  307.     GetDItem(dlg, item, &kind, &hdl, &box);
  308.     return (ControlHandle) hdl;
  309. }
  310.  
  311. static pascal short GetDirDlgHook(short item, DialogPtr dlgPtr)
  312. {
  313.     switch (item) {
  314.     case sfHookFirstCall:
  315.         if (customPrompt)
  316.             setitext(Handle(GetDlgCtrl(dlgPtr, 13)), customPrompt);
  317.         break;
  318.     case 11:
  319.         if (reply.fType) {
  320.             if (!reply.fName[0])
  321.                 currentDir    =    reply.fType;
  322.             else {
  323.                 TFileSpec dir(reply.vRefNum, CurDirStore, reply.fName);
  324.     
  325.                 dir += "\p";
  326.                 
  327.                 currentDir = dir.parID;
  328.             }
  329.                 
  330.             return    1;
  331.         }
  332.         break;
  333.     
  334.     case 12:
  335.         currentDir    =    CurDirStore;
  336.         
  337.         return 1;
  338.     case sfHookNullEvent:
  339.         if (!reply.fType)
  340.             HiliteControl(GetDlgCtrl(dlgPtr, 11), 255);
  341.         else
  342.             HiliteControl(GetDlgCtrl(dlgPtr, 11), 0);
  343.         break;
  344.     }
  345.     
  346.     return item;
  347. }
  348.  
  349. static int do_getfolder(
  350.                     char *            prompt,
  351.                     TFileSpec *     defaultFile, 
  352.                     TFileSpec *     result)
  353. {
  354.     Point        myPoint    =    {75, 75};
  355.     
  356.     if (defaultFile) {
  357.         *defaultFile += "\p";
  358.         
  359.         SFSaveDisk     = -defaultFile->vRefNum;
  360.         CurDirStore = defaultFile->parID;
  361.     }
  362.     
  363.     customPrompt = prompt && *prompt ? prompt : nil;
  364.     
  365.     SFPGetFile(
  366.         myPoint, 
  367.         "\p", 
  368.         FolderFFilter, 
  369.         -1, 
  370.         nil, 
  371.         GetDirDlgHook, 
  372.         &reply,
  373.         GUSIRsrcID,                
  374.         nil);
  375.  
  376.     if (reply.good) {
  377.         result->vRefNum    =    -SFSaveDisk;
  378.         result->parID        =    currentDir;
  379.         --*result;
  380.     }
  381.     
  382.     return reply.good;
  383. }
  384.  
  385. static int     do_putfile(    
  386.                     char    *            prompt,
  387.                     TFileSpec *     defaultFile, 
  388.                     TFileSpec *     result)
  389. {
  390.     Point            myPoint    =    {75, 75};
  391.     StringPtr    defName;
  392.     Str255        prmpt;
  393.     
  394.     prompt = (char *) memccpy((char *) prmpt + 1, prompt, 0, 254);
  395.     
  396.     if (prompt)
  397.         prmpt[0] = prompt - (char *) prmpt - 2;
  398.     else
  399.         prmpt[0] = 254;
  400.         
  401.     if (defaultFile) {
  402.         SFSaveDisk     = -defaultFile->vRefNum;
  403.         CurDirStore = defaultFile->parID;
  404.         defName        = defaultFile->name;
  405.     } else
  406.         defName        = "\p";
  407.     
  408.     SFPutFile(myPoint, prmpt, defName, NULL, &reply);
  409.     
  410.     if (reply.good)
  411.         *result        = TFileSpec(reply.vRefNum, reply.fName);
  412.     
  413.     return reply.good;
  414. }
  415.  
  416. int FileSocketDomain::choose(int, char * prompt, void * constraint, int flags, void * name, int * namelen)
  417. {
  418.     sa_constr_file *     constr = (sa_constr_file *) constraint;
  419.     TFileSpec            file;
  420.     TFileSpec            df;
  421.     TFileSpec *            defaultFile;
  422.     Boolean                good;
  423.     char *                path;
  424.     int                    len;
  425.     
  426.     if (flags & CHOOSE_DEFAULT) {
  427.         df = TFileSpec((char *) name);
  428.         defaultFile = df.Error() ? nil : &df;
  429.     } else
  430.         defaultFile = nil;
  431.         
  432.     if (flags & CHOOSE_NEW)
  433.         good = do_putfile(prompt, defaultFile, &file);
  434.     else if (flags & CHOOSE_DIR)
  435.         good = do_getfolder(prompt, defaultFile, &file);
  436.     else if (constr)
  437.         good = do_getfile(defaultFile, &file, constr->numTypes, constr->types);
  438.     else
  439.         good = do_getfile(defaultFile, &file, -1, nil);
  440.     
  441.     if (good) {
  442.         path    =    file.FullPath();
  443.         len    =    strlen(path);
  444.         
  445.         if (len < *namelen)
  446.             memcpy(name, path, (*namelen = len)+1);
  447.         else
  448.             return GUSI_error(EINVAL);
  449.     } else
  450.         return GUSI_error(EINTR);
  451.     
  452.     return 0;
  453. }
  454.  
  455. /************************ FileSocket members ************************/
  456.  
  457. int FileSocket::read(void * buffer, int buflen)
  458. {
  459.     return file_read(fd, (char *) buffer, buflen);
  460. }
  461.  
  462. int FileSocket::write(void * buffer, int buflen)
  463. {
  464.     return file_write(fd, (char *) buffer, buflen);
  465. }
  466.  
  467. int FileSocket::fcntl(unsigned int cmd, int arg)
  468. {
  469.     return file_fcntl(fd, cmd, arg);
  470. }
  471.  
  472. int FileSocket::ioctl(unsigned int request, void *argp)
  473. {
  474.     return file_ioctl(fd, request, (long *) argp);
  475. }
  476.  
  477. static OSErr GetFDCatInfo(int fd, CInfoPBRec & cb);
  478. static OSErr GetVolume(CInfoPBRec & cb, ParamBlockRec & pb);
  479. static int do_stat(const CInfoPBRec & cb, const ParamBlockRec & pb, struct stat & buf);
  480.  
  481. int FileSocket::fstat(struct stat * buf)
  482. {
  483.     CInfoPBRec        cb;
  484.     ParamBlockRec    pb;
  485.  
  486.     if (GetFDCatInfo(fd, cb)) {
  487.     
  488.         // Pseudofile
  489.         
  490.         buf->st_dev            =    0;
  491.         buf->st_ino            =    0;
  492.         buf->st_mode        =    S_IFCHR | 0666;
  493.         buf->st_nlink        =    1;
  494.         buf->st_uid            =    0;
  495.         buf->st_gid            =    0;
  496.         buf->st_rdev        =    0;
  497.         buf->st_size        =    1;
  498.         buf->st_atime        =    time(NULL);
  499.         buf->st_mtime        =    time(NULL);
  500.         buf->st_ctime        =    time(NULL);
  501.         buf->st_blksize    =    1;
  502.         buf->st_blocks        =    1;
  503.  
  504.         return 0;
  505.     } else if (GetVolume(cb, pb)) {
  506.         errno = ENOENT;
  507.  
  508.         return -1;
  509.     } else
  510.         return do_stat(cb, pb, *buf);
  511. }
  512.  
  513. long FileSocket::lseek(long offset, int whence)
  514. {
  515.     long    res;
  516.     Ptr    buf;
  517.  
  518.     res = file_lseek(fd, offset, whence);
  519.     
  520.     if (res != -1)
  521.         return res;
  522.         
  523.     if (whence != SEEK_SET) {
  524.         res = file_lseek(fd, 0, whence);
  525.         
  526.         if (res == -1)
  527.             return res;
  528.             
  529.         offset += res;
  530.     }
  531.     
  532.     res = file_lseek(fd, 0, SEEK_END);
  533.     
  534.     buf = NewPtrClear(1024);
  535.     
  536.     while (offset >= res + 1024)
  537.         if (file_write(fd, buf, 1024) == -1)
  538.             return -1;
  539.         else
  540.             res += 1024;
  541.  
  542.     if (offset > res && file_write(fd, buf, unsigned(offset-res)) == -1)
  543.         return -1;
  544.  
  545.     return 0;
  546. }
  547.  
  548. int FileSocket::ftruncate(long offset)
  549. {
  550.     if (lseek(offset, SEEK_SET) == -1)
  551.         return -1;
  552.     
  553.     if (file_ioctl(fd, FIOSETEOF, (long *) offset) == -1)
  554.         return -1;
  555.     
  556.     return 0;
  557. }
  558.  
  559. int FileSocket::isatty()
  560. {
  561.     short    fRef;
  562.     
  563.     return file_ioctl(fd, FIOREFNUM, (long *) &fRef) == -1;
  564. }
  565.  
  566. int FileSocket::select(Boolean * canRead, Boolean * canWrite, Boolean *)
  567. {
  568.     int    goodies    =    0;
  569.     
  570.     // Simplicistic implementation 
  571.     
  572.     if (canRead)    {
  573.         *canRead = true;
  574.         ++goodies;
  575.     }
  576.     
  577.     if (canWrite)    {
  578.         *canWrite = true;
  579.         ++goodies;
  580.     }
  581.     
  582.     return goodies;
  583. }
  584.  
  585. FileSocket::~FileSocket()
  586. {
  587.     file_close(fd);
  588. }
  589.  
  590. /***************** Things that happen to files only *****************/
  591.  
  592. int creat(const char* filename)
  593. {
  594.     return open(filename, O_WRONLY | O_TRUNC | O_CREAT);
  595. }
  596.  
  597. int remove(const char *filename)
  598. {
  599.     return faccess((char*) filename, F_DELETE, 0);
  600. }
  601.  
  602. int unlink(char*filename)
  603. {
  604.     return faccess((char*) filename, F_DELETE, 0);
  605. }
  606.  
  607. int rename(const char *oldname, const char *newname)
  608. {    
  609.     if (IsDevice(oldname))
  610.         return GUSI_error(EINVAL);
  611.     if (IsDevice(newname))
  612.         return GUSI_error(EINVAL);
  613.         
  614.     TFileSpec    oldnm(oldname, true);
  615.     TFileSpec    newnm(newname, true);
  616.     
  617.     return File_error(FSpSmartMove(&oldnm, &newnm));
  618. }
  619.  
  620. void fsetfileinfo(char *filename, unsigned long newcreator, unsigned long newtype)
  621. {
  622.     if (IsDevice(filename)) {
  623.         GUSI_error(EINVAL);
  624.         
  625.         return;
  626.     }
  627.         
  628.     TFileSpec    name(filename);
  629.     FInfo            info;    
  630.  
  631.     if (name.Error() || !name.Exists() || HGetFInfo(name.vRefNum, name.parID, name.name, &info)) {
  632.         GUSI_error(EIO);
  633.         
  634.         return;
  635.     }
  636.     
  637.     info.fdType     =    newtype;
  638.     info.fdCreator    =    newcreator;
  639.     
  640.     if (HSetFInfo(name.vRefNum, name.parID, name.name, &info))
  641.         GUSI_error(EIO);
  642.     
  643.     errno = 0;
  644. }
  645.  
  646. void fgetfileinfo(char *filename, unsigned long * creator, unsigned long * type)
  647. {
  648.     if (IsDevice(filename)) {
  649.         GUSI_error(EINVAL);
  650.         
  651.         return;
  652.     }
  653.         
  654.     TFileSpec    name(filename);
  655.     FInfo            info;    
  656.  
  657.     if (name.Error() || !name.Exists() || HGetFInfo(name.vRefNum, name.parID, name.name, &info)) {
  658.         GUSI_error(EIO);
  659.         
  660.         return;
  661.     }
  662.     
  663.     if (creator)
  664.         *creator = info.fdCreator;
  665.     
  666.     if (type)
  667.         *type = info.fdType;
  668.     
  669.     errno = 0;
  670. }
  671.  
  672. OSErr VRef2Icon(short vRef, Handle * icon)
  673. {
  674.     OSErr                err;
  675.     HParmBlkPtr        hpp;
  676.     ParmBlkPtr        pp;
  677.     HParamBlockRec    hpb;
  678.     
  679.     hpp                                =    &hpb;
  680.     pp                                    =    (ParmBlkPtr) hpp;
  681.     hpp->volumeParam.ioVRefNum    =    vRef;
  682.     hpp->volumeParam.ioNamePtr    =    nil;
  683.     hpp->volumeParam.ioVolIndex=    0;
  684.     if (err = PBHGetVInfoSync(hpp))
  685.         return err;
  686.         
  687.     pp->cntrlParam.ioVRefNum    =    hpb.volumeParam.ioVDrvInfo;
  688.     pp->cntrlParam.ioCRefNum    =    hpb.volumeParam.ioVDRefNum;
  689.     pp->cntrlParam.csCode        =    21;
  690.     
  691.     if (err = PBControlSync(pp))
  692.         return err;
  693.     
  694.     PtrToHand(*(Ptr *) pp->cntrlParam.csParam, icon, 256);
  695.     
  696.     return noErr;
  697. }
  698.  
  699. typedef OSType    TTypeMap[2];
  700.  
  701. static TTypeMap map[]    =    {
  702.     {'amnu', 'faam'},
  703.     {'ctrl', 'fact'},
  704.     {'extn', 'faex'},
  705.     {'pref', 'fapf'},
  706.     {'prnt', 'fapn'},
  707.     {'empt', 'trsh'},
  708.     {'trsh', 'trsh'},
  709.     {'strt', 'fast'},
  710.     {'macs', 'fasy'},
  711.     {     0,      0}
  712. };
  713.  
  714. #ifdef GUSI_FILE_DEBUG
  715. ostream & operator<<(ostream & str, OSType * ty)
  716. {
  717.     return str     << "'"
  718.                     << char((*ty >> 24) & 0xFF) 
  719.                     << char((*ty >> 16) & 0xFF)
  720.                     << char((*ty >> 8) & 0xFF)
  721.                     << char(*ty & 0xFF)
  722.                     << "'";
  723. }
  724. #endif
  725.  
  726. void OurResidentAliasExpert(
  727.     TFileSpec & file, 
  728.     OSType *     fCreator, 
  729.     OSType *     fType,
  730.     TFileSpec * iconFile,
  731.     short *         iconID)
  732. {
  733.     Boolean                        appleShare;
  734.     CInfoPBRec                    info;
  735.     GetVolParmsInfoBuffer    volParms;
  736.     HParamBlockRec                pb;
  737.     
  738.     *fCreator = 'MACS';
  739.     *iconFile    =    file;
  740.     *iconID        =    kCustomIconResource;
  741.     
  742.     if (file.parID == fsRtParID)
  743.         appleShare    =    true;
  744.     else {
  745.         if (file.CatInfo(info))
  746.             goto error;
  747.         
  748.         appleShare = !IsFile(info);
  749.     }
  750.     
  751.     if (appleShare)    {
  752.         pb.ioParam.ioNamePtr    =    nil;
  753.         pb.ioParam.ioVRefNum    =    file.vRefNum;
  754.         pb.ioParam.ioBuffer    =    Ptr(&volParms);
  755.         pb.ioParam.ioReqCount=    sizeof(GetVolParmsInfoBuffer);
  756.         
  757.         if (PBHGetVolParmsSync(&pb) || !volParms.vMServerAdr)    
  758.             appleShare    =    false;
  759.     }
  760.     
  761.     if (appleShare)
  762.         if (file.parID == fsRtParID)
  763.             *fType    =    'srvr';
  764.         else if (!HasRdPerm(info))
  765.             *fType     =    'fadr';
  766.         else
  767.             *fType    =    'faet';
  768.     else if (file.parID == fsRtParID)
  769.         *fType    =    'hdsk';
  770.     else if (!IsFile(info)) 
  771.         if (DirIsMounted(info))
  772.             *fType = 'famn';
  773.         else if (DirIsExported(info))
  774.             *fType = 'fash';
  775.         else if (DirIsShared(info))
  776.             *fType = 'faet';
  777.         else 
  778.             *fType = 'fdrp';
  779.  
  780.     if (file.parID == fsRtParID)    {
  781.         iconFile->parID    =    fsRtDirID;
  782.         PLstrcpy(iconFile->name, "\pIcon\n");
  783.     } else if (!IsFile(info))    {
  784.         if (info.dirInfo.ioDrDirID < 9)    {
  785.             short vRef;
  786.             long    dirID;
  787.             
  788.             for (TTypeMap * mapp = map; **mapp; ++mapp)
  789.                 if (!FindFolder(file.vRefNum, (*mapp)[0], false, &vRef, &dirID))
  790.                     if (dirID == info.dirInfo.ioDrDirID) {
  791.                         *fType = (*mapp)[1];
  792.  
  793.                         break;
  794.                     }
  795.         }
  796.         *iconFile += "\pIcon\n";
  797.     } else {
  798.         *fType    =    info.hFileInfo.ioFlFndrInfo.fdType;
  799.         *fCreator=    info.hFileInfo.ioFlFndrInfo.fdCreator;
  800.     }
  801.     
  802. #ifdef GUSI_FILE_DEBUG
  803.     cerr << "Type = " << fType << ", creator = " << fCreator << endl;
  804.     cerr << "Look for custom icons in " << iconFile->FullPath() << endl;
  805. #endif
  806.  
  807.     return;
  808. error:
  809.     *fType        =    0;
  810.     *fCreator    =    0;
  811. }
  812.  
  813. static OSType iconTypes[]    =    {
  814.     'ICN#',
  815.     'ics#',
  816.     'icl4',
  817.     'ics4',
  818.     'icl8', 
  819.     'ics8',
  820.     0
  821. };
  822.  
  823. Boolean CopyIconFamily(short srcResFile, short srcID, short dstResFile, short dstID)
  824. {
  825.     Handle    icon;
  826.     Boolean    success    =    false;
  827.     OSType * types;
  828.  
  829.     for (types = iconTypes; *types; ++types)    {
  830.         UseResFile(srcResFile);
  831.         if (icon = Get1Resource(*types, srcID))    {
  832.             UseResFile(dstResFile);
  833.             DetachResource(icon);
  834.             AddResource(icon, *types, dstID, "\p");
  835.         
  836.             success = success || !ResError();
  837.         }
  838.     }
  839.     
  840.     return success;
  841. }
  842.  
  843. Boolean AddIconsToFile(
  844.     const TFileSpec &    origFile,
  845.     short                 aliasFile, 
  846.     OSType                 fCreator, 
  847.     OSType                fType, 
  848.     const FSSpec &        iconFile, 
  849.     short                    iconID)
  850. {
  851.     short        iFile;
  852.     Boolean    success;
  853.     Handle     icon;
  854.  
  855.     iFile = FSpOpenResFile(&iconFile, fsRdPerm);
  856.     
  857.     if (iFile == -1)
  858.         goto noCustom;
  859.     
  860.     success = CopyIconFamily(iFile, iconID, aliasFile, kCustomIconResource);
  861.     
  862.     CloseResFile(iFile);
  863.     
  864.     if (success)
  865.         return true;
  866.  
  867. #ifdef GUSI_FILE_DEBUG
  868.     cerr << "No custom Icons found." << endl;
  869. #endif
  870.  
  871. noCustom:    
  872.     if (fType == 'hdsk' && fCreator == 'MACS')
  873.         if (!VRef2Icon(origFile.vRefNum, &icon))    {
  874. #ifdef GUSI_FILE_DEBUG
  875.             cerr << "Found icon for disk drive." << endl;
  876. #endif
  877.             AddResource(icon, 'ICN#', kCustomIconResource, "\p");
  878.             
  879.             return !ResError();
  880.         }
  881.                 
  882.     return false;
  883. }
  884.  
  885. int symlink(const char* linkto, const char* linkname)
  886. {
  887.     if (IsDevice(linkto))
  888.         return GUSI_error(EINVAL);
  889.     if (IsDevice(linkname))
  890.         return GUSI_error(EINVAL);
  891.         
  892.     OSType        fType;
  893.     OSType        fCreator;
  894.     short            iconID;
  895.     short            aliasFile;
  896.     AliasHandle    alias;
  897.     Boolean        customIcon;
  898.     TFileSpec    iconFile;
  899.     FInfo            info;
  900.     
  901.     if (!hasAlias || !hasMakeFSSpec)
  902.         return GUSI_error(EOPNOTSUPP);
  903.         
  904.     TFileSpec    oldnm(linkto);
  905.     
  906.     if (oldnm.Error() || !oldnm.Exists())
  907.         return GUSI_error(EIO);
  908.         
  909.     TFileSpec    newnm(linkname, true);
  910.  
  911.     if (newnm.Error())
  912.         return GUSI_error(EIO);
  913.     
  914.     if (newnm.Exists())
  915.         return GUSI_error(EEXIST);
  916.     
  917.     OurResidentAliasExpert(oldnm, &fCreator, &fType, &iconFile, &iconID);
  918.     
  919. #ifdef GUSI_FILE_DEBUG
  920.     cerr << "Creating " << newnm.FullPath() << endl;
  921. #endif
  922.  
  923.     FSpCreateResFile(&newnm, fCreator, fType, smSystemScript);
  924.     
  925.     if (ResError())
  926.         return GUSI_error(EIO);
  927.     
  928. #ifdef GUSI_FILE_DEBUG
  929.     cerr << "Opening " << newnm.FullPath() << endl;
  930. #endif
  931.  
  932.     aliasFile = FSpOpenResFile(&newnm, fsRdWrPerm);
  933.     
  934.     if (aliasFile == -1)
  935.         goto deleteFile;
  936.     
  937. #ifdef GUSI_FILE_DEBUG
  938.     cerr << "Creating alias for " << oldnm.FullPath() << " in " << newnm.FullPath() << endl;
  939. #endif
  940.     
  941.     if (NewAlias(nil, &oldnm, &alias))
  942.         goto closeFile;
  943.  
  944. #ifdef GUSI_FILE_DEBUG
  945.     cerr << "Adding alias to file." << endl;
  946. #endif
  947.     
  948.     AddResource((Handle) alias, 'alis', 0, oldnm.name);
  949.     
  950.     if (ResError())
  951.         goto deleteAlias;
  952.     
  953.     customIcon = AddIconsToFile(oldnm, aliasFile, fCreator, fType, iconFile, iconID);
  954.  
  955. #ifdef GUSI_FILE_DEBUG
  956.     cerr << "There were " << (customIcon ? "" : "no ") << "custom Icons." << endl;
  957. #endif
  958.         
  959.     CloseResFile(aliasFile);
  960.  
  961.     FSpGetFInfo(&newnm, &info);
  962.     info.fdFlags    |=    (1 << 15) | (customIcon ? (1 << 10) : 0);
  963.     info.fdFlags    &= ~(1 << 8);
  964.     FSpSetFInfo(&newnm, &info);
  965.     
  966.     return 0;
  967.  
  968. deleteAlias:
  969.     DisposHandle((Handle) alias);
  970. closeFile:
  971.     CloseResFile(aliasFile);
  972. deleteFile:
  973.     FSpDelete(&newnm);    
  974.     
  975.     return GUSI_error(EIO);
  976. }
  977.  
  978. int readlink(const char * path, char * buf, int bufsiz)
  979. {
  980.     if (IsDevice(path))
  981.         return GUSI_error(EINVAL);
  982.         
  983.     char *         end;
  984.     TFileSpec    file(path, true);
  985.     CInfoPBRec    info;
  986.     
  987.     if (file.CatInfo(info))
  988.         goto error;
  989.         
  990.     if (!IsAlias(info))
  991.         return GUSI_error(EINVAL);
  992.     
  993.     if (file.Resolve())
  994.         goto error;
  995.  
  996.     end = (char *) memccpy(buf, file.FullPath(), 0, bufsiz);
  997.     
  998.     if (!end)
  999.         return GUSI_error(ENAMETOOLONG);
  1000.     else
  1001.         return end - buf - 1;
  1002.         
  1003. error:
  1004.     return File_error(file.Error());
  1005. }
  1006.  
  1007. int faccess(char* filename, unsigned int cmd, long* arg)
  1008. {
  1009.     if (IsDevice(filename))
  1010.         return file_faccess(filename, cmd, arg);
  1011.         
  1012.     TFileSpec    file(filename, cmd == F_DELETE);
  1013.     
  1014.     if (file.Error())
  1015.         return File_error(file.Error());
  1016.     else
  1017.         return file_faccess(file.RelPath(), cmd, arg);
  1018. }
  1019.  
  1020. int truncate(const char* filename, off_t offset)
  1021. {
  1022.     int    res;
  1023.     int    fd    =     open(filename, O_RDWR);
  1024.     
  1025.     if (fd == -1)
  1026.         return -1;
  1027.     
  1028.     res = ftruncate(fd, offset);
  1029.  
  1030.     close(fd);
  1031.     
  1032.     return res;
  1033. }
  1034.  
  1035. static OSErr GetFDCatInfo(int fd, CInfoPBRec & cb)
  1036. {
  1037.     short                fRef;
  1038.     OSErr                err;
  1039.     FCBPBRec            fcb;
  1040.     Str255            fname;
  1041.  
  1042.     if (file_ioctl(fd, FIOREFNUM, (long *) &fRef) == -1)
  1043.         return fnfErr;
  1044.  
  1045.     fcb.ioNamePtr    =     fname;
  1046.     fcb.ioRefNum    =    fRef;
  1047.     fcb.ioFCBIndx    =     0;
  1048.     if (err = PBGetFCBInfoSync(&fcb))
  1049.         return err;
  1050.  
  1051.     cb.hFileInfo.ioNamePtr        =    fname;
  1052.     cb.hFileInfo.ioDirID            =    fcb.ioFCBParID;
  1053.     cb.hFileInfo.ioVRefNum        =    fcb.ioFCBVRefNum;
  1054.     cb.hFileInfo.ioFDirIndex    =    0;
  1055.  
  1056.     return PBGetCatInfoSync(&cb);
  1057. }
  1058.  
  1059. static OSErr GetVolume(CInfoPBRec & cb, ParamBlockRec & pb)
  1060. {
  1061.     Str63                name;
  1062.  
  1063.     pb.volumeParam.ioNamePtr    =    name;
  1064.     pb.volumeParam.ioVRefNum    =    cb.hFileInfo.ioVRefNum;
  1065.     pb.volumeParam.ioVolIndex    =    0;
  1066.  
  1067.     return PBGetVInfo(&pb, false);
  1068. }
  1069.  
  1070. static int do_stat(const CInfoPBRec & cb, const ParamBlockRec & pb, struct stat & buf)
  1071. {
  1072.     buf.st_dev        =    pb.ioParam.ioVRefNum;
  1073.     buf.st_ino        =    cb.dirInfo.ioDrDirID;
  1074.     buf.st_nlink    =    1;
  1075.     buf.st_uid        =    0;
  1076.     buf.st_gid        =    0;
  1077.     buf.st_rdev        =    0;
  1078.     buf.st_atime    =    cb.hFileInfo.ioFlMdDat;
  1079.     buf.st_mtime    =    cb.hFileInfo.ioFlMdDat;
  1080.     buf.st_ctime    =    cb.hFileInfo.ioFlCrDat;
  1081.     buf.st_blksize    =    pb.volumeParam.ioVAlBlkSiz;
  1082.  
  1083.     if (!IsFile(cb))    {
  1084.         TFileSpec        spec;
  1085.         CInfoPBRec        info;
  1086.  
  1087.         spec.vRefNum    =    pb.ioParam.ioVRefNum;
  1088.         spec.parID        =    cb.dirInfo.ioDrDirID;
  1089.         
  1090.         ++buf.st_nlink;
  1091.         
  1092.         if (GUSIConfig.accurStat) {
  1093.             for (int i = 0; i++ < cb.dirInfo.ioDrNmFls;) {
  1094.                 spec    =    spec[i];
  1095.                 if (!spec.Error() && !spec.CatInfo(info) && !IsFile(info))
  1096.                     ++buf.st_nlink;
  1097.             }
  1098.         } else {
  1099.             buf.st_nlink    +=    cb.dirInfo.ioDrNmFls;
  1100.         }
  1101.         
  1102.         buf.st_mode    =    S_IFDIR | 0777;
  1103.         buf.st_size    =    cb.dirInfo.ioDrNmFls;
  1104.     } else if (IsAlias(cb)) {
  1105.         buf.st_mode    =    S_IFLNK | 0777;
  1106.         buf.st_size    =    cb.hFileInfo.ioFlRLgLen;        /* Data fork is ignored    */
  1107.     } else if (cb.hFileInfo.ioFlFndrInfo.fdType == '∑OCK') {
  1108.         buf.st_mode    =    S_IFSOCK | 0666;
  1109.         buf.st_size    =    cb.hFileInfo.ioFlRLgLen;        /* Data fork is ignored    */
  1110.     } else {
  1111.         buf.st_mode    =    S_IFREG | 0666;
  1112.  
  1113.         if (cb.hFileInfo.ioFlAttrib & 0x01)
  1114.             buf.st_mode&=    ~0222;
  1115.  
  1116.         switch (cb.hFileInfo.ioFlFndrInfo.fdType) {
  1117.         case 'APPL':
  1118.         case 'MPST':
  1119.         case 'TEXT':
  1120.             buf.st_mode|=    0111;
  1121.             break;
  1122.         default:
  1123.             break;
  1124.         }
  1125.         
  1126.         buf.st_size    =    cb.hFileInfo.ioFlLgLen;        /* Resource fork is ignored    */
  1127.     }
  1128.  
  1129.     buf.st_blocks    =    (buf.st_size + buf.st_blksize - 1) / buf.st_blksize;
  1130.  
  1131.     return 0;
  1132. }
  1133.  
  1134. static int do_special_stat(struct stat & buf)
  1135. {
  1136.     buf.st_dev            =    0;
  1137.     buf.st_ino            =    0;
  1138.     buf.st_mode            =    S_IFCHR | 0666 ;
  1139.     buf.st_nlink        =    1;
  1140.     buf.st_uid            =    0;
  1141.     buf.st_gid            =    0;
  1142.     buf.st_rdev            =    0;
  1143.     buf.st_size            =    1;
  1144.     buf.st_atime        =    time(NULL);
  1145.     buf.st_mtime        =    time(NULL);
  1146.     buf.st_ctime        =    time(NULL);
  1147.     buf.st_blksize        =    1;
  1148.     buf.st_blocks        =    1;
  1149.     
  1150.     return 0;
  1151. }
  1152.  
  1153. int stat(const char * path, struct stat * buf)
  1154. {
  1155.     CInfoPBRec        cb;
  1156.     ParamBlockRec    pb;
  1157.     
  1158.     if (IsDevice(path)) {
  1159.         return do_special_stat(*buf);
  1160.     } else {
  1161.         TFileSpec        spec(path);
  1162.     
  1163.         if (spec.Error() || spec.CatInfo(cb) || GetVolume(cb, pb)) {
  1164.             errno = ENOENT;
  1165.     
  1166.             return -1;
  1167.         } else 
  1168.             return do_stat(cb, pb, *buf);
  1169.     }
  1170. }
  1171.  
  1172. int    lstat(const char * path, struct stat * buf)
  1173. {
  1174.     CInfoPBRec        cb;
  1175.     ParamBlockRec    pb;
  1176.  
  1177.     if (IsDevice(path)) {
  1178.         return do_special_stat(*buf);
  1179.     } else {
  1180.         TFileSpec        spec(path, true);
  1181.     
  1182.         if (spec.Error() || spec.CatInfo(cb) || GetVolume(cb, pb)) {
  1183.             errno = ENOENT;
  1184.     
  1185.             return -1;
  1186.         } else 
  1187.             return do_stat(cb, pb, *buf);
  1188.     }
  1189. }
  1190.  
  1191. int utime(const char * path, const struct utimbuf * times)
  1192. {
  1193.     if (IsDevice(path))
  1194.         return GUSI_error(EINVAL);
  1195.     
  1196.     TFileSpec        spec(path);
  1197.     CInfoPBRec        cb;
  1198.  
  1199.     if (spec.Error() || spec.CatInfo(cb))
  1200.         return GUSI_error(ENOENT);
  1201.     
  1202.     cb.hFileInfo.ioVRefNum    =    spec.vRefNum;
  1203.     cb.hFileInfo.ioDirID        =    spec.parID;
  1204.     cb.hFileInfo.ioNamePtr    =    spec.name;
  1205.     cb.hFileInfo.ioFlMdDat    =    times ? times->modtime : time(nil);
  1206.     // times->actime is ignored. The Mac has no access times.
  1207.     
  1208.     return File_error(PBSetCatInfoSync(&cb));
  1209. }
  1210.  
  1211. /************************* directory stuff **************************/
  1212.  
  1213. struct dir {
  1214.     short            index;
  1215.     short            vol;
  1216.     long            dirID;
  1217.     dirent        entry;
  1218. };
  1219.  
  1220. DIR * opendir(const char * name)
  1221. {
  1222.     DIR *            d;
  1223.     TFileSpec    spec(name);
  1224.     
  1225.     if (spec.Error())
  1226.         goto error;
  1227.     
  1228.     spec += "\p";
  1229.     
  1230.     if (spec.Error())
  1231.         goto error;
  1232.     
  1233.     d = (DIR *) NewPtr(sizeof(DIR));
  1234.     
  1235.     d->index    =    1;
  1236.     d->vol    =    spec.vRefNum;
  1237.     d->dirID    =    spec.parID;
  1238.     
  1239.     return d;
  1240.     
  1241. error:
  1242.     File_error(spec.Error());
  1243.     
  1244.     return nil;
  1245. }
  1246.     
  1247. struct dirent * readdir(DIR * dirp)
  1248. {
  1249.     TFileSpec    spec;
  1250.     int             i; 
  1251.     int            e = errno;
  1252.     
  1253.     spec.vRefNum    =    dirp->vol;
  1254.     spec.parID        =    dirp->dirID;
  1255.     
  1256.     spec = spec[dirp->index++];
  1257.     
  1258.     if (spec.Error())
  1259.         goto error;
  1260.     
  1261.     dirp->entry.d_fileno    =    spec.LastInfo()->dirInfo.ioDrDirID;
  1262.     dirp->entry.d_namlen = *spec.name;
  1263.     
  1264.     memcpy(dirp->entry.d_name, (char *) spec.name+1, dirp->entry.d_namlen);
  1265.     
  1266.     dirp->entry.d_name[dirp->entry.d_namlen] = 0;
  1267.     
  1268.     i = dirp->entry.d_namlen;
  1269.     do 
  1270.         dirp->entry.d_name[i++] = 0;
  1271.     while (i & 3);
  1272.     
  1273.     dirp->entry.d_reclen = sizeof(u_long)+sizeof(u_short)+sizeof(u_short)+i;
  1274.     
  1275.     return &dirp->entry;
  1276.     
  1277. error:
  1278.     File_error(spec.Error());
  1279.     
  1280.     if (errno == ENOENT)
  1281.         errno = e;
  1282.         
  1283.     return nil;
  1284. }
  1285.  
  1286. long telldir(const DIR * dirp)
  1287. {
  1288.     return dirp->index;
  1289. }
  1290.  
  1291. void seekdir(DIR * dirp, long loc)
  1292. {
  1293.     dirp->index    =    (short) loc;
  1294. }
  1295.  
  1296. void rewinddir(DIR * dirp)
  1297. {
  1298.     dirp->index    =    1;
  1299. }
  1300.  
  1301. int closedir(DIR * dirp)
  1302. {
  1303.     DisposPtr((Ptr) dirp);
  1304.     
  1305.     return 0;
  1306. }
  1307.  
  1308. int scandir(
  1309.     const char *         name, 
  1310.     struct dirent *** namelist,
  1311.    int (*want)(struct dirent *), 
  1312.     int (*cmp)(const void *, const void *))
  1313. {
  1314.     struct dirent *    entry;
  1315.     struct dirent *    copy;
  1316.     struct dirent **    names;
  1317.     int                     count;
  1318.     DIR *                    dirp;
  1319.     CInfoPBRec            info;
  1320.     TFileSpec            spec;
  1321.     
  1322.     if ((dirp = opendir(name)) == NULL)
  1323.         return -1;
  1324.  
  1325.     spec.vRefNum    =    dirp->vol;
  1326.     spec.parID        =    dirp->dirID;
  1327.  
  1328.     if (spec.CatInfo(info))
  1329.         return File_error(spec.Error());
  1330.  
  1331.     names = (struct dirent **) malloc(info.dirInfo.ioDrNmFls * sizeof(struct dirent *));
  1332.     if (names == NULL)
  1333.         return GUSI_error(ENOMEM);
  1334.  
  1335.     count = 0;
  1336.     while ((entry = readdir(dirp)) != NULL) {
  1337.         if (want && !(*want)(entry))
  1338.             continue;    /* Don't want this entry */
  1339.  
  1340.         if (!(copy = (struct dirent *)malloc(entry->d_reclen))) {
  1341.             free(names);
  1342.             
  1343.             return GUSI_error(ENOMEM);
  1344.         }
  1345.         
  1346.         memcpy(copy, entry, entry->d_reclen);
  1347.  
  1348.         names[count++] = copy;
  1349.     }
  1350.     
  1351.     closedir(dirp);
  1352.     
  1353.     if (count && cmp)
  1354.         qsort(names, count, sizeof(struct dirent *), cmp);
  1355.         
  1356.     *namelist = names;
  1357.     
  1358.     return count;
  1359. }
  1360.  
  1361. int chdir(const char * path)    
  1362. {
  1363.     TFileSpec    dir(path);
  1364.     
  1365.     if (dir.Error())
  1366.         return GUSI_error(ENOENT);
  1367.         
  1368.     return File_error(TFileSpec::ChDir(dir));
  1369. }
  1370.  
  1371. int mkdir(const char * path)    
  1372. {
  1373.     OSErr            err;
  1374.     long            nuDir;
  1375.     TFileSpec    dir(path, true);
  1376.     
  1377.     if (dir.Error())
  1378.         return File_error(dir.Error());
  1379.     
  1380.     if (err = DirCreate(dir.vRefNum, dir.parID, dir.name, &nuDir))
  1381.         return File_error(err);
  1382.  
  1383.     return 0;
  1384. }
  1385.  
  1386. int rmdir(const char * path)    
  1387. {
  1388.     OSErr            err;
  1389.     TFileSpec    dir(path);
  1390.     
  1391.     if (dir.Error())
  1392.         return GUSI_error(ENOENT);
  1393.  
  1394.     if (err = HDelete(dir.vRefNum, dir.parID, dir.name))
  1395.         switch (err)    {
  1396.         default:
  1397.             return File_error(err);
  1398.         case dirFulErr:
  1399.             return GUSI_error(ENOTEMPTY);
  1400.         }
  1401.     
  1402.     return 0;
  1403. }
  1404.  
  1405. char * getcwd(char * buf, size_t size)
  1406. {
  1407.     OSErr            err;
  1408.     TFileSpec    cwd;
  1409.     char *         res;
  1410.     
  1411.     if (err = cwd.Default()) {
  1412.         File_error(err);
  1413.     
  1414.         return nil;
  1415.     }
  1416.         
  1417.     res = cwd.FullPath();
  1418.     
  1419.     if (size < strlen(res)+1)
  1420.         return (char *) GUSI_error_nil(ENAMETOOLONG);
  1421.     if (!buf && !(buf = (char *) malloc(size)))
  1422.         return (char *) GUSI_error_nil(ENOMEM);
  1423.  
  1424.     strcpy(buf, res);
  1425.     
  1426.     return buf;
  1427. }